#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>

#include "lcd_dev.h"
#include "lcd_drv.h"

int g_lcd_default_size = LCD_FONT_SIZE16;

static char ascii64[][16] = {
// #include "ascii64.dat"
};

static char ascii32[][16] = {
// #include "ascii32.dat"
};

static char ascii16[] = {
#include "ascii16.dat"
};

static void lcd_put_char(int x, int y, int width, int height, char *p, int bkcolor, int ftcolor);

int lcd_clear(int color)
{
    for (int y = 0; y < SCREEN_HEIGHT; y++) {
        for (int x = 0; x < SCREEN_WIDTH; x++) {
            lcd_put_pixel(x, y, color);
        }
    }
    return 0;
}

void lcd_put_ascii16(int x, int y, char c, int bkcolor, int ftcolor)
{
    char *dots = &ascii16[c * 16];
    int i;

    for (i = 0; i < 16; i++) {
        for (int j = 0; j < 8; j++) {
            if (0x01 == ((dots[i] >> (7 - j)) & 0x01)) {
                lcd_put_pixel(x + j, y + i, ftcolor);
            } else {
                lcd_put_pixel(x + j, y + i, bkcolor);
            }
        }
    }
}

void lcd_put_ascii_str16(int x, int y, char *str, int bkcolor, int ftcolor)
{
    int pos = 0;

    do {
        lcd_put_ascii16(x + pos, y, *str, bkcolor, ftcolor);
        pos += 8;
        str ++;
    } while (*str != '\0');
}

void lcd_put_ascii_str64(int x, int y, char *str, int bkcolor, int ftcolor)
{
    int index;
    char *p = (char *)ascii64;

    do {
        index = ((*str) - 0x20 ) * 64 * 4;
        lcd_put_char(x, y, 4, 64, p + index, bkcolor, ftcolor);

        x += 32;
        str ++;
    } while (*str != '\0');
}

void lcd_put_ascii_str32(int x, int y, char *str, int bkcolor, int ftcolor)
{
    int index;
    char *p = (char *)ascii32;

    do {
        index = ((*str) - 0x20 ) * 32 * 2;						// 鐠侊紕鐣荤€涙膩閸嬪繒些閿涘奔绮犵粚鐑樼壐瀵偓婵拷
        lcd_put_char(x, y, 2, 32, p + index, bkcolor, ftcolor);	//  閺勫墽銇氭稉鈧稉顏勭摟缁楋拷

        x += 16;		// 缁夎濮╅崗澶嬬垼
        str ++;			// 娑撳绔存稉顏勭摟缁楋拷
    } while (*str != '\0');
}

static void lcd_put_char(int x, int y, int width, int height, char *p, int bkcolor, int ftcolor)
{
    int i;
    int j;
    int k;

    for (i = 0; i < height; i ++) {
        for (j = 0; j < width; j ++) {
            for (k = 0; k < 8; k ++) {
                if (((p[i * width + j] >> (7 - k)) & 0x01) == 0x01) {
                    lcd_put_pixel(x + j * 8 + k, i + y, ftcolor);
                } else {
                    lcd_put_pixel(x + j * 8 + k, i + y, bkcolor);
                }
            }
        }
    }
}

void lcd_put_ascii_str(int line, int col, char *str, int mode)
{
    if (g_lcd_default_size == LCD_FONT_SIZE64) {
        if (mode == LCD_DISPLAY_NORMAL) {
            lcd_put_ascii_str64(col * 32, line * 64, str, LCD_FRONT_COLOR, LCD_BACK_COLOR);
        } else {
            lcd_put_ascii_str64(col * 32, line * 64, str, LCD_BACK_COLOR, LCD_FRONT_COLOR);
        }
    } else if (g_lcd_default_size == LCD_FONT_SIZE32) {
        if (mode == LCD_DISPLAY_NORMAL) {
            lcd_put_ascii_str32(col * 16, line * 32, str, LCD_FRONT_COLOR, LCD_BACK_COLOR);
        } else {
            lcd_put_ascii_str32(col * 16, line * 32, str, LCD_BACK_COLOR, LCD_FRONT_COLOR);
        }
    } else if (g_lcd_default_size == LCD_FONT_SIZE16) {
        if (mode == LCD_DISPLAY_NORMAL) {
            lcd_put_ascii_str16(col * 8, line * 16, str, LCD_FRONT_COLOR, LCD_BACK_COLOR);
        } else {
            lcd_put_ascii_str16(col * 8, line * 16, str, LCD_BACK_COLOR, LCD_FRONT_COLOR);
        }
    }
}

void lcd_printf(int line, int col, const char *fmt, ...)
{
    va_list args;
    char printbuffer[100];
    va_start (args, fmt);

    vsprintf (printbuffer, fmt, args);

    va_end (args);
    lcd_put_ascii_str(line, col, printbuffer, LCD_DISPLAY_NORMAL);
}

void lcd_put_rect(int x, int y, int width, int height, int color)
{
    int i;
    int j;

    for (i = 0; i < height; i ++) {
        for (j = 0; j < width; j ++) {
            lcd_put_pixel(x + j, y + i, color);
        }
    }
}

void lcd_put_line(int x1, int y1, int x2, int y2, int color)
{
    float k, b;

    if (x1 == x2) {
        if (y1 > y2) {
            int t = y1;
            y1 = y2;
            y2 = t;
        }
        for (int y = y1; y <= y2; y++) {
            lcd_put_pixel(x1, y, color);
        }
        return;
    }

    k = (float)(y2 - y1) / (x2 - x1);
    b = y1 - k * x1;

    if (x1 > x2) {
        int t = x1;
        x1 = x2;
        x2 = t;
    }

    for (int x = x1; x <= x2; x++) {
        int y = k * x + b;
        lcd_put_pixel(x, y, color);
    }
}

void lcd_put_circle(int x0, int y0, int r, int color)
{
    int x = r;
    int y = 0;
    int err = 0;

    while (x >= y) {
        lcd_put_pixel(x0 + x, y0 + y, color);
        lcd_put_pixel(x0 + y, y0 + x, color);
        lcd_put_pixel(x0 - y, y0 + x, color);
        lcd_put_pixel(x0 - x, y0 + y, color);
        lcd_put_pixel(x0 - x, y0 - y, color);
        lcd_put_pixel(x0 - y, y0 - x, color);
        lcd_put_pixel(x0 + y, y0 - x, color);
        lcd_put_pixel(x0 + x, y0 - y, color);

        if (err <= 0) {
            y += 1;
            err += 2 * y + 1;
        }
        if (err > 0) {
            x -= 1;
            err -= 2 * x + 1;
        }
    }
}

void lcd_put_hzk16(int x, int y, char *pdat, int mode)
{
    FILE *fp;
    char buf[32];
    int i;
    int j;
    int front;	// front color
    int	back;	// back color
    unsigned int fpos;
    unsigned int ab;
    unsigned int cd;

    fp = fopen("HZK16", "rb");
    if (NULL == fp) {
        printf("Can NOT open file HZK16\n");
        return;
    }

    ab	= (pdat[0] - 0xa1) & 0xff;
    cd	= (pdat[1] - 0xa1) & 0xff;
    fpos = (ab * 94 + cd) * 32;
    fseek(fp, fpos, SEEK_SET);
    fread(buf, 1, 32, fp);
    fclose(fp);

    if (LCD_DISPLAY_NORMAL == mode) {
        front	= LCD_FRONT_COLOR;
        back	= LCD_BACK_COLOR;
    } else {
        front	= LCD_BACK_COLOR;
        back	= LCD_FRONT_COLOR;
    }

    for (i = 0; i < 16; i++) {
        for (j = 0; j < 8; j++) {
            if (0x01 == ((buf[2 * i] >> (7 - j)) & 0x01)) {
                lcd_put_pixel(x + j, y + i, front);
            } else {
                lcd_put_pixel(x + j, y + i, back);
            }

            if (0x01 == ((buf[2 * i + 1] >> (7 - j)) & 0x01)) {
                lcd_put_pixel(x + j + 8, y + i, front);
            } else {
                lcd_put_pixel(x + j + 8, y + i, back);
            }
        }
    }
}

extern void utf2gbk(char *str, char *outbuf);
void lcd_put_str16(int x, int y, char *pstr, int mode)
{
    int	cnt;
    int ftcolor;
    int bkcolor;
    char gbk[3] = {0};
    char utf8[4] = {0};

    if (LCD_DISPLAY_NORMAL == mode) {
        ftcolor	= LCD_FRONT_COLOR;
        bkcolor	= LCD_BACK_COLOR;
    } else {
        ftcolor	= LCD_BACK_COLOR;
        bkcolor	= LCD_FRONT_COLOR;
    }

    x *= 8;
    y *= 16;

    cnt	= 0;
    while (*pstr != '\0') {
        if (*pstr >> 7) {	// hz
            memcpy(utf8, pstr, 3);
            utf2gbk(utf8, gbk);
            lcd_put_hzk16(x + cnt, y, gbk, mode);
            pstr += 3;  // utf-8 is 3 bytes or 4 bytes, here we only consider 3 bytes
            cnt	+= 16;
            if (SCREEN_WIDTH - x - cnt < 16) {
                x    = 0;
                cnt  = 0;   //new line
                y   += 16;
            }

        } else {
            lcd_put_ascii16(x + cnt, y, *pstr, bkcolor, ftcolor);
            pstr++;
            cnt	+= 8;
            if (SCREEN_WIDTH - x - cnt < 8) {
                x    = 0;
                cnt  = 0;   //new line
                y   += 16;
            }
        }
    }
}

void lcd_put_str(int x, int y, char *pstr, int mode)
{
    if (g_lcd_default_size == LCD_FONT_SIZE64) {
        // lcd_put_str64(x, y, pstr, LCD_BACK_COLOR, LCD_FRONT_COLOR);
    } else if (g_lcd_default_size == LCD_FONT_SIZE32) {
        // lcd_put_str32(x, y, pstr, LCD_BACK_COLOR, LCD_FRONT_COLOR);
    } else if (g_lcd_default_size == LCD_FONT_SIZE16) {
        lcd_put_str16(x, y, pstr, mode);
    } else if (g_lcd_default_size == LCD_FONT_SIZE12) {
        lcd_put_str12(x, y, pstr, LCD_BACK_COLOR, LCD_FRONT_COLOR);
    }
}

void lcd_put_ascii12(int x, int y, char c, int bkcolor, int ftcolor)
{
    char *dots = &ascii16[c * 16];
    int i;

    for (i = 0; i < 12; i++) {
        for (int j = 0; j < 6; j++) {
            if (0x01 == ((dots[i] >> (7 - j)) & 0x01)) {
                lcd_put_pixel(x + j, y + i, ftcolor);
            } else {
                lcd_put_pixel(x + j, y + i, bkcolor);
            }
        }
    }
}

void lcd_put_hzk12(int x, int y, char *pdat, int mode)
{
    FILE *fp;
    char buf[24];
    int i;
    int j;
    int front;	// front color
    int	back;	// back color
    unsigned int fpos;
    unsigned int ab;
    unsigned int cd;

    fp = fopen("HZK12", "rb");
    if (NULL == fp) {
        printf("Can NOT open file HZK12\n");
        return;
    }

    ab	= (pdat[0] - 0xa1) & 0xff;
    cd	= (pdat[1] - 0xa1) & 0xff;
    fpos = (ab * 94 + cd) * 24;
    fseek(fp, fpos, SEEK_SET);
    fread(buf, 1, 24, fp);
    fclose(fp);

    if (LCD_DISPLAY_NORMAL == mode) {
        front	= LCD_FRONT_COLOR;
        back	= LCD_BACK_COLOR;
    } else {
        front	= LCD_BACK_COLOR;
        back	= LCD_FRONT_COLOR;
    }

    for (i = 0; i < 24; i++) {
        for (j = 0; j < 6; j++) {
            if (0x01 == ((buf[2 * i] >> (7 - j)) & 0x01)) {
                lcd_put_pixel(x + j, y + i, front);
            } else {
                lcd_put_pixel(x + j, y + i, back);
            }

            if (0x01 == ((buf[2 * i + 1] >> (7 - j)) & 0x01)) {
                lcd_put_pixel(x + j + 6, y + i, front);
            } else {
                lcd_put_pixel(x + j + 6, y + i, back);
            }
        }
    }
}

void lcd_put_str12(int x, int y, char *pstr, int mode)
{
    int	cnt;
    int ftcolor;
    int bkcolor;
    char gbk[3] = {0};
    char utf8[4] = {0};

    if (LCD_DISPLAY_NORMAL == mode) {
        ftcolor	= LCD_FRONT_COLOR;
        bkcolor	= LCD_BACK_COLOR;
    } else {
        ftcolor	= LCD_BACK_COLOR;
        bkcolor	= LCD_FRONT_COLOR;
    }

    x *= 8;
    y *= 16;

    cnt	= 0;
    while (*pstr != '\0') {
        if (*pstr >> 7) {	// hz
            memcpy(utf8, pstr, 3);
            utf2gbk(utf8, gbk);
            lcd_put_hzk12(x + cnt, y, gbk, mode);
            pstr += 3;  // utf-8 is 3 bytes or 4 bytes, here we only consider 3 bytes
            cnt	+= 12;
            if (SCREEN_WIDTH - x - cnt < 24) {
                x    = 0;
                cnt  = 0;   //new line
                y   += 12;
            }

        } else {
            lcd_put_ascii12(x + cnt, y, *pstr, bkcolor, ftcolor);
            pstr++;
            cnt	+= 8;
            if (SCREEN_WIDTH - x - cnt < 12) {
                x    = 0;
                cnt  = 0;   //new line
                y   += 12;
            }
        }
    }
}

void lcd_put_icon24(int x, int y, char *p, int mode)
{
    int ftcolor;
    int bkcolor;

    if (LCD_DISPLAY_NORMAL == mode) {
        ftcolor	= LCD_FRONT_COLOR;
        bkcolor	= LCD_BACK_COLOR;
    } else {
        ftcolor	= LCD_BACK_COLOR;
        bkcolor	= LCD_FRONT_COLOR;
    }

    for (int i = 0; i < 24; i++) {
        for (int j = 0; j < 3; j++) {
            for (int k = 0; k < 8; k++) {
                if (0x01 == ((p[i * 3 + j] >> (7 - k)) & 0x01)) {
                    lcd_put_pixel(x + j * 8 + k, i + y, ftcolor);
                } else {
                    lcd_put_pixel(x + j * 8 + k, i + y, bkcolor);
                }
            }
        }
    }
}


